/*****************************************************************************
 * ijksdl_aout_android_audiotrack.c
 *****************************************************************************
 *
 * Copyright (c) 2013 Bilibili
 * copyright (c) 2013 Zhang Rui <bbcallen@gmail.com>
 *
 * This file is part of ijkPlayer.
 *
 * ijkPlayer is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * ijkPlayer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with ijkPlayer; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

//#include "ijksdl_aout_android_audiotrack.h"
#include "ijksdl_aout_SDL_audio.h"
#include <stdbool.h>
#include <assert.h>
//#include "./../android/jni.h"
#include "../ijksdl_inc_internal.h"
//#include "../ijksdl_thread.h"
#include "../ijksdl_aout_internal.h"
//#include "./../android/ijksdl_android_jni.h"
//#include "./../android/android_audiotrack.h"
#include "libavutil/common.h"
#include "libavutil/channel_layout.h"
#include "ff_ffplay_def.h"

#ifdef SDLTRACE
#undef SDLTRACE
#define SDLTRACE(...)
//#define SDLTRACE ALOGE
#endif

static SDL_Class g_audioSDL_class = {
        .name = "AudioTrack",
};


typedef struct SDL_Aout_Opaque {
//    SDL_cond *wakeup_cond;
//    SDL_mutex *wakeup_mutex;

//    SDL_AudioSpec spec;
//    SDL_Android_AudioTrack* atrack;
//    uint8_t *buffer;
//    int buffer_size;

//    volatile bool need_flush;
//    volatile bool pause_on;
//    volatile bool abort_request;
//
//    volatile bool need_set_volume;
//    volatile float left_volume;
//    volatile float right_volume;

//    SDL_Thread *audio_tid;
//    SDL_Thread _audio_tid;

//    int audio_session_id;
//
//    volatile float speed;
//    volatile bool speed_changed;



    SDL_AudioDeviceID audio_dev;
    struct AudioParams *audio_hw_params
} SDL_Aout_Opaque;

//static int aout_thread_n(JNIEnv *env, SDL_Aout *aout)
//{
//    SDL_Aout_Opaque *opaque = aout->opaque;
//    SDL_Android_AudioTrack *atrack = opaque->atrack;
//    SDL_AudioCallback audio_cblk = opaque->spec.callback;
//    void *userdata = opaque->spec.userdata;
//    uint8_t *buffer = opaque->buffer;
//    int copy_size = 256;
//
//    assert(atrack);
//    assert(buffer);
//
//    SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
//
//    if (!opaque->abort_request && !opaque->pause_on)
//        SDL_Android_AudioTrack_play(env, atrack);
//
//    while (!opaque->abort_request) {
//        SDL_LockMutex(opaque->wakeup_mutex);
//        if (!opaque->abort_request && opaque->pause_on) {
//            SDL_Android_AudioTrack_pause(env, atrack);
//            while (!opaque->abort_request && opaque->pause_on) {
//                SDL_CondWaitTimeout(opaque->wakeup_cond, opaque->wakeup_mutex, 1000);
//            }
//            if (!opaque->abort_request && !opaque->pause_on) {
//                if (opaque->need_flush) {
//                    opaque->need_flush = 0;
//                    SDL_Android_AudioTrack_flush(env, atrack);
//                }
//                SDL_Android_AudioTrack_play(env, atrack);
//            }
//        }
//        if (opaque->need_flush) {
//            opaque->need_flush = 0;
//            SDL_Android_AudioTrack_flush(env, atrack);
//        }
//        if (opaque->need_set_volume) {
//            opaque->need_set_volume = 0;
//            SDL_Android_AudioTrack_set_volume(env, atrack, opaque->left_volume, opaque->right_volume);
//        }
//        if (opaque->speed_changed) {
//            opaque->speed_changed = 0;
//            SDL_Android_AudioTrack_setSpeed(env, atrack, opaque->speed);
//        }
//        SDL_UnlockMutex(opaque->wakeup_mutex);
//
//        audio_cblk(userdata, buffer, copy_size);
//        if (opaque->need_flush) {
//            SDL_Android_AudioTrack_flush(env, atrack);
//            opaque->need_flush = false;
//        }
//
//        if (opaque->need_flush) {
//            opaque->need_flush = 0;
//            SDL_Android_AudioTrack_flush(env, atrack);
//        } else {
//            int written = SDL_Android_AudioTrack_write(env, atrack, buffer, copy_size);
//            if (written != copy_size) {
//                ALOGW("AudioTrack: not all data copied %d/%d", (int)written, (int)copy_size);
//            }
//        }
//
//        // TODO: 1 if callback return -1 or 0
//    }
//
//    SDL_Android_AudioTrack_free(env, atrack);
//    return 0;
//}


//static int aout_thread(void *arg)
//{
//    SDL_Aout *aout = arg;
//    int env = 0;
//    return aout_thread_n(env, aout);
//}
//static int aout_open_SDL_audio_n(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
//{
//    SDL_Aout_Opaque *opaque = aout->opaque;
//    SDL_AudioSpec wanted_spec, spec;
//    const char *env;
//    static const int next_nb_channels[] = {0, 0, 1, 6, 2, 6, 4, 6};
//    static const int next_sample_rates[] = {0, 44100, 48000, 96000, 192000};
//    int next_sample_rate_idx = FF_ARRAY_ELEMS(next_sample_rates) - 1;
//
//    int64_t wanted_channel_layout = 0;// = desired->channels;
//    int wanted_nb_channels = desired->channels;
//    int wanted_sample_rate = desired->freq;
//
//    env = SDL_getenv("SDL_AUDIO_CHANNELS");
//    if (env) {
//        wanted_nb_channels = atoi(env);
//        wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels);
//    }
//    if (!wanted_channel_layout || wanted_nb_channels != av_get_channel_layout_nb_channels(wanted_channel_layout)) {
//        wanted_channel_layout = av_get_default_channel_layout(wanted_nb_channels);
//        wanted_channel_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX;
//    }
//    wanted_nb_channels = av_get_channel_layout_nb_channels(wanted_channel_layout);
//    wanted_spec.channels = wanted_nb_channels;
//    wanted_spec.freq = wanted_sample_rate;
//    if (wanted_spec.freq <= 0 || wanted_spec.channels <= 0) {
//        av_log(NULL, AV_LOG_ERROR, "Invalid sample rate or channel count!\n");
//        return -1;
//    }
//
//    while (!(opaque->audio_dev = SDL_OpenAudioDevice(NULL, 0, &wanted_spec, &spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_CHANNELS_CHANGE))) {
//        av_log(NULL, AV_LOG_WARNING, "SDL_OpenAudio (%d channels, %d Hz): %s\n",
//               wanted_spec.channels, wanted_spec.freq, SDL_GetError());
//        wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)];
//        if (!wanted_spec.channels) {
//            wanted_spec.freq = next_sample_rates[next_sample_rate_idx--];
//            wanted_spec.channels = wanted_nb_channels;
//            if (!wanted_spec.freq) {
//                av_log(NULL, AV_LOG_ERROR,
//                       "No more combinations to try, audio open failed\n");
//                return -1;
//            }
//        }
//        wanted_channel_layout = av_get_default_channel_layout(wanted_spec.channels);
//    }
//
//    if (spec.format != AUDIO_S16SYS) {
//        av_log(NULL, AV_LOG_ERROR,
//               "SDL advised audio format %d is not supported!\n", spec.format);
//        return -1;
//    }
//    if (spec.channels != wanted_spec.channels) {
//        wanted_channel_layout = av_get_default_channel_layout(spec.channels);
//        if (!wanted_channel_layout) {
//            av_log(NULL, AV_LOG_ERROR,
//                   "SDL advised channel count %d is not supported!\n", spec.channels);
//            return -1;
//        }
//    }
//
//    opaque->audio_hw_params->fmt = AV_SAMPLE_FMT_S16;
//    opaque->audio_hw_params->freq = spec.freq;
//    opaque->audio_hw_params->channel_layout = wanted_channel_layout;
//    opaque->audio_hw_params->channels =  spec.channels;
//    opaque->audio_hw_params->frame_size = av_samples_get_buffer_size(NULL, opaque->audio_hw_params->channels, 1, opaque->audio_hw_params->fmt, 1);
//    opaque->audio_hw_params->bytes_per_sec = av_samples_get_buffer_size(NULL, opaque->audio_hw_params->channels, opaque->audio_hw_params->freq, opaque->audio_hw_params->fmt, 1);
//    if (opaque->audio_hw_params->bytes_per_sec <= 0 || opaque->audio_hw_params->frame_size <= 0) {
//        av_log(NULL, AV_LOG_ERROR, "av_samples_get_buffer_size failed\n");
//        return -1;
//    }
//    return spec.size;
//}

//static void aout_close_audio(SDL_Aout *aout);
//static int aout_open_audio_n(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
//{
//    assert(desired);
//    SDL_Aout_Opaque *opaque = aout->opaque;
//
//    opaque->spec = *desired;
//
//    opaque->buffer_size = aout_open_SDL_audio_n(aout, desired, obtained);
//    if (opaque->buffer_size <= 0) {
//        ALOGE("aout_open_audio_n: failed to getMinBufferSize()");
////        SDL_Android_AudioTrack_free(env, opaque->atrack);
////        opaque->atrack = NULL;
//        goto failed;
//    }
//
//    opaque->buffer = malloc(opaque->buffer_size);
//    if (!opaque->buffer) {
//        ALOGE("aout_open_audio_n: failed to allocate buffer");
////        SDL_Android_AudioTrack_free(env, opaque->atrack);
////        opaque->atrack = NULL;
//        goto failed;
//    }
//
////    if (obtained) {
////        SDL_Android_AudioTrack_get_target_spec(opaque->atrack, obtained);
////        SDLTRACE("audio target format fmt:0x%x, channel:0x%x", (int)obtained->format, (int)obtained->channels);
////    }
//
////    opaque->audio_session_id = SDL_Android_AudioTrack_getAudioSessionId(env, opaque->atrack);
//    ALOGI("audio_dev = %d\n", opaque->audio_dev);
//
//    opaque->pause_on = 1;
//    opaque->abort_request = 0;
////    opaque->audio_tid = SDL_CreateThread(aout_thread, "ff_aout_android", aout);
////    if (!opaque->audio_tid) {
////        ALOGE("aout_open_audio_n: failed to create audio thread");
////        SDL_Android_AudioTrack_free(env, opaque->atrack);
////        opaque->atrack = NULL;
////        return -1;
////    }
//
//    return 0;
//failed:
//    //TODO
//    //close audio dev
//    aout_close_audio(aout);
//    return -1;
//}


static int aout_open_audio(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
{
    assert(desired);
    SDL_Aout_Opaque *opaque = aout->opaque;
    opaque->audio_dev = SDL_OpenAudioDevice(NULL, 0, desired, obtained, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_CHANNELS_CHANGE);
    return opaque->audio_dev;
}
//
static void aout_pause_audio(SDL_Aout *aout, int pause_on)
{
    SDL_Aout_Opaque *opaque = aout->opaque;
//
//    SDL_LockMutex(opaque->wakeup_mutex);
//    SDLTRACE("aout_pause_audio(%d)", pause_on);
//    opaque->pause_on = pause_on;
//    if (!pause_on)
//        SDL_CondSignal(opaque->wakeup_cond);

//pause_on only 0
//
    av_log(NULL, AV_LOG_WARNING, "SDL_PauseAudioDevice, may block ,pause_on:%d\n", pause_on);
    SDL_PauseAudioDevice(opaque->audio_dev, pause_on);

//    SDL_UnlockMutex(opaque->wakeup_mutex);
}
//
//static void aout_flush_audio(SDL_Aout *aout)
//{
//    SDL_Aout_Opaque *opaque = aout->opaque;
//    SDL_LockMutex(opaque->wakeup_mutex);
//    SDLTRACE("aout_flush_audio()");
//    opaque->need_flush = 1;
//    SDL_CondSignal(opaque->wakeup_cond);
//    SDL_UnlockMutex(opaque->wakeup_mutex);
//}
//
//static void aout_set_volume(SDL_Aout *aout, float left_volume, float right_volume)
//{
//    SDL_Aout_Opaque *opaque = aout->opaque;
//    SDL_LockMutex(opaque->wakeup_mutex);
//    SDLTRACE("aout_flush_audio()");
//    opaque->left_volume = left_volume;
//    opaque->right_volume = right_volume;
//    opaque->need_set_volume = 1;
//    SDL_CondSignal(opaque->wakeup_cond);
//    SDL_UnlockMutex(opaque->wakeup_mutex);
//}

static void aout_close_audio(SDL_Aout *aout)
{
    SDL_Aout_Opaque *opaque = aout->opaque;
    SDL_CloseAudioDevice(opaque->audio_dev);
}

static void aout_free_l(SDL_Aout *aout)
{
    if (!aout)
        return;

    aout_close_audio(aout);

    SDL_Aout_Opaque *opaque = aout->opaque;
//    if (opaque) {
//        free(opaque->buffer);
//        opaque->buffer = NULL;
//        opaque->buffer_size = 0;
//
//        SDL_DestroyCond(opaque->wakeup_cond);
//        SDL_DestroyMutex(opaque->wakeup_mutex);
//    }

    SDL_Aout_FreeInternal(aout);
}

//static void func_set_playback_rate(SDL_Aout *aout, float speed)
//{
//    if (!aout)
//        return;
//
//    SDL_Aout_Opaque *opaque = aout->opaque;
//    SDL_LockMutex(opaque->wakeup_mutex);
//    SDLTRACE("%s %f", __func__, (double)speed);
//    opaque->speed = speed;
//    opaque->speed_changed = 1;
//    SDL_CondSignal(opaque->wakeup_cond);
//    SDL_UnlockMutex(opaque->wakeup_mutex);
//}

SDL_Aout *SDL_AoutSDL_CreateForAudio()
{
    SDL_Aout *aout = SDL_Aout_CreateInternal(sizeof(SDL_Aout_Opaque));
    if (!aout)
        return NULL;

    SDL_Aout_Opaque *opaque = aout->opaque;
//    opaque->wakeup_cond  = SDL_CreateCond();
//    opaque->wakeup_mutex = SDL_CreateMutex();
//    opaque->speed        = 1.0f;

    aout->opaque_class = &g_audioSDL_class;
    aout->free_l       = aout_free_l;
    aout->open_audio   = aout_open_audio;
    aout->pause_audio  = aout_pause_audio;
//    aout->flush_audio  = aout_flush_audio;
//    aout->set_volume   = aout_set_volume;
    aout->close_audio  = aout_close_audio;
//    aout->func_get_audio_session_id = aout_get_audio_session_id;
//    aout->func_set_playback_rate    = func_set_playback_rate;

    return aout;
}
